package com.dkts.oil.service.impl;

import com.dkts.oil.config.OilConfig;
import com.dkts.oil.converter.BoundingBoxUtil;
import com.dkts.oil.converter.UtilsGeoGrid;
import com.dkts.oil.exception.OilException;
import com.dkts.oil.service.impl.address.CbkSitesHelper;
import com.dkts.oil.service.impl.address.WcgySitesHelper;
import com.dkts.oil.service.impl.address.XhkSitesHelper;
import com.dkts.oil.service.impl.address.ZyzSitesHelper;
import com.dkts.oil.web.vo.request.SiteSelectionRequest;
import com.dkts.oil.web.vo.response.AddressPlanResponse;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.Geometry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
@Slf4j
public class AddressPlanV3ServiceImpl {

    @Autowired
    private OilConfig oilConfig;

    @Autowired
    private WcgySitesHelper wcgySitesHelper;

    @Autowired
    private XhkSitesHelper xhkSitesHelper;

    @Autowired
    private ZyzSitesHelper zyzSitesHelper;

    @Autowired
    private CbkSitesHelper cbkSitesHelper;

    private String wcgySitesName = "外出供油中心";
    private String xhkSitesName = "消耗库";
    private String zyzSitesName = "转运站";
    private String cbkSitesName = "储备库";

    /**
     * 主方法，基于格子生成多个方案
     */
    public List<AddressPlanResponse.PlanItem> oilStorageV3(
            SiteSelectionRequest request,
            Geometry planGeometry,
            List<Geometry> obstacles
    ) throws Exception {
        if (obstacles == null) {
            obstacles = new ArrayList<>();
        }
        //外出供油中心
        List<AddressPlanResponse.Site> wcgySites = wcgySites(request, request.getDefaultPolygon(), obstacles);
        check(wcgySites, wcgySitesName, request.getAreaConfig().getFuelSupplyCenterArea(), obstacles);

        //消耗库
        List<AddressPlanResponse.Site> xhkSites = xhkSites(request, planGeometry, obstacles);
        check(xhkSites, xhkSitesName, request.getAreaConfig().getConsumptionDepotArea(), obstacles);

        //转运站
        List<AddressPlanResponse.Site> zyzSites = zyzSites(request, planGeometry, obstacles);
        check(zyzSites, zyzSitesName, request.getAreaConfig().getTransferStationArea(), obstacles);

        //储备库
        List<AddressPlanResponse.Site> cbkSites = cbkSites(request, planGeometry, obstacles);
        check(cbkSites, cbkSitesName, request.getAreaConfig().getReserveDepotArea(), obstacles);
        return resultPlans(wcgySites, xhkSites, zyzSites, cbkSites);
    }

    private List<AddressPlanResponse.Site> wcgySites(SiteSelectionRequest request, Geometry planGeometry, List<Geometry> obstacles) throws Exception {
        List<Geometry> wcgyGeometries = addObstacles(obstacles, planGeometry, request.getAreaConfig().getFuelSupplyCenterArea());
        return wcgySitesHelper.addressPlan(request, planGeometry, wcgyGeometries, wcgySitesName);
    }

    private List<AddressPlanResponse.Site> xhkSites(SiteSelectionRequest request, Geometry planGeometry, List<Geometry> obstacles) throws Exception {
        List<Geometry> wcgyGeometries = addObstacles(obstacles, planGeometry, request.getAreaConfig().getFuelSupplyCenterArea());
        return xhkSitesHelper.addressPlan(request, planGeometry, wcgyGeometries, obstacles, xhkSitesName);
    }

    private List<AddressPlanResponse.Site> zyzSites(SiteSelectionRequest request, Geometry planGeometry, List<Geometry> obstacles) throws Exception {
        List<Geometry> wcgyGeometries = addObstacles(obstacles, planGeometry, request.getAreaConfig().getFuelSupplyCenterArea());
        return zyzSitesHelper.addressPlan(request, planGeometry, wcgyGeometries, obstacles, zyzSitesName);
    }

    private List<AddressPlanResponse.Site> cbkSites(SiteSelectionRequest request, Geometry planGeometry, List<Geometry> obstacles) throws Exception {
        List<Geometry> wcgyGeometries = addObstacles(obstacles, planGeometry, request.getAreaConfig().getFuelSupplyCenterArea());
        return cbkSitesHelper.addressPlan(request, planGeometry, wcgyGeometries, obstacles, cbkSitesName);
    }

    private List<Geometry> addObstacles(List<Geometry> obstacles, Geometry planGeometry, double area) throws Exception {
        List<Geometry> gridGeometries = UtilsGeoGrid.gridGeometryInfo(
                planGeometry,
                BoundingBoxUtil.getBoundingBox(planGeometry),
                true,
                Math.sqrt(area),
                obstacles,
                oilConfig.getTempDir(), 5000, 6
        );
        return gridGeometries;
    }

    private void check(List<AddressPlanResponse.Site> sites, String name, double area, List<Geometry> obstacles) {
        if (sites == null || sites.size() == 0) {
            throw new OilException("没有找到对应的" + name + ",没有找到可用" + area + "面积");
        }
        for (AddressPlanResponse.Site site : sites) {
            obstacles.add(site.getGeometry());
        }
    }

    private List<AddressPlanResponse.PlanItem> resultPlans(List<AddressPlanResponse.Site> wcgySites,
                                                  List<AddressPlanResponse.Site> xhkSites,
                                                  List<AddressPlanResponse.Site> zyzSites,
                                                  List<AddressPlanResponse.Site> cbkSites
    ) {
        List<AddressPlanResponse.PlanItem> resultPlans = new ArrayList<>();

        // 确保选址方案数是一样的，找出最小的数量
        int maxPlans = 3;

        // 生成最多三个选址方案，每个方案包含四个站点
        for (int i = 0; i < maxPlans; i++) {

            AddressPlanResponse.PlanItem planItem = new AddressPlanResponse.PlanItem();

            // 如果某个类型的站点数量不足3个，使用第一个站点
            planItem.setWcgyzx(i < wcgySites.size() ? wcgySites.get(i) : wcgySites.get(0));
            planItem.setXhk(i < xhkSites.size() ? xhkSites.get(i) : xhkSites.get(0));
            planItem.setZyz(i < zyzSites.size() ? zyzSites.get(i) : zyzSites.get(0));
            planItem.setCbk(i < cbkSites.size() ? cbkSites.get(i) : cbkSites.get(0));

            // 将方案加入结果列表
            resultPlans.add(planItem);
        }

        return resultPlans;
    }

}
